﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Diagnostics;

namespace ProgNetComponents.Design
{
    /// <summary>
    /// GeneralAbstractTypeDescriptionProvider
    /// </summary>
    /// <typeparam name="TAbstract">The type of the abstract.</typeparam>
    /// <typeparam name="TConcentrate">The type of the concentrate.</typeparam>
    public abstract class GeneralAbstractTypeDescriptionProvider<TAbstract, TConcentrate> : TypeDescriptionProvider
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="GeneralAbstractTypeDescriptionProvider{TAbstract, TConcentrate}"/> class.
        /// </summary>
        public GeneralAbstractTypeDescriptionProvider()
            : base(TypeDescriptor.GetProvider(typeof(TAbstract)))
        {

        }

        /// <summary>
        /// Creates an object that can substitute for another data type.
        /// </summary>
        /// <param name="provider">An optional service provider.</param>
        /// <param name="objectType">The type of object to create. This parameter is never null.</param>
        /// <param name="argTypes">An optional array of types that represent the parameter types to be passed to the object's constructor. This array can be null or of zero length.</param>
        /// <param name="args">An optional array of parameter values to pass to the object's constructor.</param>
        /// <returns>
        /// The substitute <see cref="T:System.Object" />.
        /// </returns>
        public override object CreateInstance(IServiceProvider provider, Type objectType, Type[] argTypes, object[] args)
        {
            if (objectType == typeof(TAbstract))
                objectType = typeof(TConcentrate);

            return base.CreateInstance(provider, objectType, argTypes, args);
        }

        /// <summary>
        /// Performs normal reflection against the given object with the given type.
        /// </summary>
        /// <param name="objectType">The type of object for which to retrieve the <see cref="T:System.Reflection.IReflect" />.</param>
        /// <param name="instance">An instance of the type. Can be null.</param>
        /// <returns>
        /// A <see cref="T:System.Type" />.
        /// </returns>
        public override Type GetReflectionType(Type objectType, object instance)
        {
            StackTrace st = new StackTrace();
            if (objectType == typeof(TAbstract) && !st.ToString().Contains("System.ComponentModel.Design.InheritanceService.AddInheritedComponents"))
                objectType = typeof(TConcentrate);
            return base.GetReflectionType(objectType, instance);
        }
    }
}
